var SCHEDULER_STATE_AVAIL="0";
var SCHEDULER_STATE_BUSY="1";
var SCHEDULER_STATE_UNAVAIL="2";
var scheduler={
	/** Time range, from:Date, to:Date */
	range:null,
	/** Time slot interval in mins, minimum interval 15 min */
	interval:-1,
	/** */
	intervals:[],
	/** List of attendees, format:[{id:string,name:string,avail:string},...] */
	attendees:[],
	/** A selected meeting range to be scheduled, s1:DateRange slot 1, s2:DateRange slot 2*/
	mtrange:{ s1:null, s2:null },
	
	availurl:"avail.php",
	acurl:"autocomplete.php",
	schedmturl:"schedmt.php",
	
	init:function( range, interval, atts ) {
		if ( range==null ) {
			var now=new Date();
			now.setMinutes(0);
			now.setSeconds(0);
			now.setMilliseconds(0);
			range=new DateRange( new Date(now.getTime()-4*3600*1000), new Date(now.getTime()+8*3600*1000) );
		}
		if ( interval==null ) {
			interval=parseInt(range.duration()/12);
		}
		this.range=range;
		this.mtrange={ s1:null, s2:null }
		this.interval=interval;
		this.attendees=atts;
		this.updateIntervals();
	},
	
	load:function() {
		var sc=$("div.ui-scheduler-control");	// Scheduler Control
		var sched=$("table.ui-scheduler"); 		// Scheduler Table
		var ts;									// Time Slot
		var sr=$("thead.ui-scheduler-range tr", sched);	// scheduler range DOM obj
		var dur=this.intervals[0].duration();			// duration of each slot
		var smk=(dur>60?(dur>24*60?"M dS":"hA"):"h:iA");// slot mask
		var sa=$("tbody.ui-scheduler-avail", sched);
		
		//@1. Load Time Slots Header
		// Do this in HTML page
		//sr.append('<td>Enter name:<br><input id="qname" type="text"></td>');
			
		//@1.1 Load the date info
		$("span.date-info").text(this.range.from.format("Y-m-d"));
		for ( var i=0; i<this.intervals.length; i++ ) {
			sr.append('<td class="ui-scheduler-time-slot">'+this.intervals[i].format(smk)+'</td>');
		}
		
		//@2. Load Attendees
		for ( var i=0; i<this.attendees.length; i++ ) {
			sa.append('<tr class="ui-scheduler-avail-user"><td><span id="'+this.attendees[i].id+'">'+this.attendees[i].name+'</span></td>'+parseAvail(this.attendees[i].avail)+'</tr>');
		}
		
		//@3. Load Controls
		var $qname=$("#qname",sched);
		$qname.autocomplete(scheduler.acurl);
		
		$("#adduser",sched).click(function() {
			var user={id:$qname[0].extra[0], name:$qname.val(), avail:null};
			// Clear the $qname field
			$qname.val("");
			$qname[0].extra[0]="";
			// Temporarily disable the controls
			sr.fadeTo("fast", 0.30);
			
			user.avail=scheduler.updateAvail(user);
			scheduler.attendees.push(user);
		});
		
		$("img[alt=Schedule]", sc).click(function () {
			var cfm;				// Confirmation string
			var mttitle;			// Meeting title
			var mtstart;			// meeting start time
			var mtend;				// meeting end time
			var mtdesc;				// meeting description
			var mtcal;				//meeting calendar
			var attsstr="";			// attendees string
			var fmt="Y-m-dTH:i:s";	// Date format
			if ( scheduler.mtrange.s1==null||scheduler.mtrange.s2==null ) {
				alert("You must select start and end time for the meeting!");
				return false;
			}
			if ( (mttitle=$("#mttitle").val())=="" ) {
				alert("Please enter a meeting title!");
				return false;
			}
			mtdesc=$("#mtdesc").val();
			mtcal=$("#mtcal").val();
			mtstart=scheduler.mtrange.s1.from.format(fmt);
			mtend=(scheduler.mtrange.s2==null?scheduler.mtrange.s1.to.format(fmt):scheduler.mtrange.s2.to.format(fmt));
			cfm="Are you sure to schedule a meeting from "+mtstart+" to "+mtend+" with the following particiapnts?\n";
			for ( var i=0; i<scheduler.attendees.length; i++ ) {
				attsstr+=scheduler.attendees[i].id+"|";
				cfm+="\t"+scheduler.attendees[i].name+"("+scheduler.attendees[i].id+")\n";
			}
			if ( confirm(cfm) ) {
			//TODO make schedmt.php
				$.post(scheduler.schedmturl, {start:mtstart,end:mtend,title:mttitle,desc:mtdesc,invitees:attsstr,caluri:mtcal},function(){});
			}
			return true;
		});
		
		$("img[alt=Reset]", sc).click(function() {
			//TODO reset will reset the range, and attendees, then refresh the table
			scheduler.init();
			sa.html("");
			scheduler.refresh();
		});
		
		$("img[alt='[-]']", sc).click(function () {
			scheduler.range.zoom(1);
			scheduler.interval*=2;
			scheduler.updateIntervals();
			scheduler.refresh();
		});
		
		$("img[alt='[+]']", sc).click(function () {
			if ( scheduler.interval<=15 ) {
				alert( "You cannot zoom in any more." );
				return false;
			}
			scheduler.range.zoom(-1);
			scheduler.interval/=2;
			scheduler.updateIntervals();
			scheduler.refresh();
		});
		
		$("img[alt='<']", sc).click(function () {
			scheduler.range.move(-1*scheduler.interval);
			scheduler.updateIntervals();
			scheduler.refresh();
		});
		
		$("img[alt='>']", sc).click(function () {
			scheduler.range.move(scheduler.interval);
			scheduler.updateIntervals();
			scheduler.refresh();
		});
		
		(ts=$("td.ui-scheduler-time-slot", sched)).click(function () {
			var idx=$("td",sr).index(this)-1;	// index of which the time slot is clicked on
			if ( scheduler.mtrange.s1==null ) {
				scheduler.mtrange.s1=scheduler.intervals[idx];
			} else if ( scheduler.mtrange.s2==null ) {
				if ( scheduler.mtrange.s1.from.compareTo(scheduler.intervals[idx].from)<=0 ) {
					scheduler.mtrange.s2=scheduler.intervals[idx];
				} else {
					scheduler.mtrange.s2=scheduler.mtrange.s1;
					scheduler.mtrange.s1=scheduler.intervals[idx];
				}
			} else {
				scheduler.mtrange.s1=scheduler.intervals[idx];
				scheduler.mtrange.s2=null;
			}
			
			shadeSelectedMeeting(scheduler.intervals, ts);
		});
	},
	
	refresh:function() {
		//@1. Refresh time slots
		var tr=$("td.ui-scheduler-time-slot");
		var dur=this.intervals[0].duration();			// duration of each slot
		var smk=(dur>60?(dur>24*60?"M dS":"hA"):"h:iA");// slot mask
		//@1.1 Update the date info
		$("span.date-info").text(this.range.from.format("Y-m-d"));
		for ( var i in this.intervals ) {
			tr[i].innerHTML=this.intervals[i].format(smk);
		}
		
		//@2. Refresh user availibilities
		var users=(this.attendees!=null&&this.attendees.length>0?$("tr.ui-scheduler-avail-user"):[]);
		var avails;
		var avail;
		for ( var i=0; i<users.length; i++ ) {
			avails=$("td",$(users[i]));
			avails[0].innerHTML='<span id="'+this.attendees[i].id+'">'+this.attendees[i].name+'</span><img alt="Remove" src="images/close.png">';
			// Load the remove attendee feature
			$("img[alt=Remove]", avails).click(function () {
				var uid=$(this).siblings("span").attr("id");
				// Remove from the attendees
				scheduler.removeAttendee(uid);
				// Remove from the table
				$(this).parent().parent().remove();
			});
			avail=this.attendees[i].avail;
			for ( var j=0; j<avail.length; j++ ) {
				switch ( avail.charAt(i) ) {
					case SCHEDULER_STATE_AVAIL:
						$("span",avails[j+1]).toggleClass("ui-scheduler-state-avail");
						break;
					case SCHEDULER_STATE_BUSY:
					case SCHEDULER_STATE_UNAVAIL:
						$("span",avails[j+1]).toggleClass("ui-scheduler-state-unavail");
						break;
				}
			}
		}
	},
	
	updateAvail:function ( user ) {
		var uids=user.id;
		var mask="Y-m-dTH:i:s";
		var avail;
		$.post(scheduler.availurl,
				{start:this.range.from.format(mask),end:this.range.to.format(mask),qmail:uids, interval:this.interval*60},
				function(data){
					var newavails=data.split("|");
					
					// Reenable the header columns
					$("thead.ui-scheduler-range tr").fadeTo("fast",1);
					
					// Load the attendees
					for ( var i=0; i<newavails.length; i++ ) {
						avail=user.avail=newavails[i];
						scheduler.loadAttendee(user);
					}
				});
		return avail;
	},
	
	loadAttendee:function( user ) {
		var sa=$("tbody.ui-scheduler-avail");
		console.debug(user.avail);
		sa.append('<tr class="ui-scheduler-avail-user"><td><span id="'+user.id+'">'+user.name+'</span><img alt="Remove" src="images/close.png"></td>'+parseAvail(user.avail)+'</tr>');
		// Load the remove attendee feature
		$("img[alt=Remove]", sa).click(function () {
			var uid=$(this).siblings("span").attr("id");
			// Remove from the attendees
			scheduler.removeAttendee(uid);
			// Remove from the table
			$(this).parent().parent().remove();
		});
	},
	
	removeAttendee:function( uid ) {
		if ( scheduler.attendees==null ) return false;
		for ( var i=0; i<scheduler.attendees.length; i++ ) {
			if ( scheduler.attendees[i].id==uid ) {
				scheduler.attendees.splice(i,1);
			}
		}
	},
	
	updateAttendees:function() {
		var uids="";
		var mask="Y-m-dTH:i:s";
		for ( var i in this.attendees ) {
			uids+=this.attendees[i].id+"|";
		}
		uids.substring(0,uids.length-1);
		$.post(scheduler.availurl, 
				{start:this.range.from.format(mask),end:this.range.to.format(mask),qmail:uids, interval:this.interval*60},
				function(data){
					var newavails=data.split("|");
					for ( var i=0; i<newavails.length; i++ ) {
						this.attendees[i].avail=newavails[i];
					}
				});
		
	},
	/** List of intervals based on range, and interval, format:[range,...] */
	updateIntervals:function() {
		this.intervals=new Array();
		var end=this.range.duration()/this.interval;
		for ( var i=0; i<end; i++ ) {
			this.intervals.push( new DateRange(new Date(this.range.from.getTime()+i*this.interval*60000),
									new Date(this.range.from.getTime()+(i+1)*this.interval*60000)) );
		}
	}
};

/**
 * @param avail string
 * 		a bit string of availabilities based on scheduler state
 *		format, ex: "002000200200"
 */
function parseAvail( avail ) {
	var ret="";
	for ( var i in avail ) {
		switch ( avail.charAt(i) ) {
			case SCHEDULER_STATE_AVAIL:
				ret+='<td><span class="ui-scheduler-state-avail">&nbsp;</span></td>';
				break;
			case SCHEDULER_STATE_BUSY:
			case SCHEDULER_STATE_UNAVAIL:
				ret+='<td><span class="ui-scheduler-state-unavail">&nbsp;</span></td>';
				break;
		}
	}
	return ret;
}

/**
 * Loop through the intervals and shade the time slots and user slots
 * @param ints
 * 		intervals, a list of time ranges
 * @param ts
 * 		time slot jquery object
 * @param us
 * 		user slot jquery object
 */
function shadeSelectedMeeting( ints, ts, us ) {
	if ( ints==null ) ints=shceduler.intervals;
	if ( ts==null ) ts=$("td.ui-scheduler-time-slot");
	if ( us==null ) us=$("tr.ui-scheduler-avail-user");
	
	var startidx=-1;
	var endidx=-1;
	var s2=scheduler.mtrange.s2;
	if (s2==null) {
		s2=scheduler.mtrange.s1;
	}
	// Loop through the intervals 
	for ( var i=0; i<ints.length; i++ ) {
		// If this range slot is in between the selected meeting
		// then shade it.
		if ( ints[i].from.compareTo(scheduler.mtrange.s1.from)>=0&&ints[i].to.compareTo(s2.to)<=0 ) {
			ts.get(i).style.backgroundColor="#CCC";
			if ( startidx<0 ) startidx=i;
		} else {
			ts.get(i).style.backgroundColor="";
			if ( startidx>=0&&endidx<0 ) endidx=i;
		}
	}
	if ( endidx<0 ) endidx=startidx+1;
	for ( var j=0; j<us.length; j++ ) {
		var tds=$("td", us.get(j));
		tds.css("backgroundColor", "");
		tds.slice(startidx+1, endidx+1).css("backgroundColor", "#ccc");
	}
}